package com.huadao.cart_ccs.common;

import com.huadao.cart_ccs.data.bo.Protocol;
import com.huadao.cart_ccs.exception.UnpackException;
import com.huadao.cart_ccs.main.CartApplication;
import com.huadao.cart_ccs.netty.TestDecoder;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class ByteUtils {

    public static byte[] generateParams(byte[] commandWord, byte[] modularOrder, byte[] orderContent) {
        byte[] head = {(byte) 0xBA};//报头

        byte[] agentNumber = CartApplication.getInstance().getAgentNumber();//代理商编号
        byte[] mac = CartApplication.getInstance().getMac();//MAC地址
        byte[] deviceType = {(byte) 0xFF};//设备类型
//        byte[] commandWord= {order};//命令字
//        byte[] modularOrder=modularOrder;//模块指令
//        byte[] orderContent=;//指令内容
        if (orderContent == null || orderContent.length == 0) {
            orderContent = new byte[]{0x00};
        }
        byte[] checkSum = new byte[1];//校验和
        byte[] tail = {(byte) 0xED};//报尾

        int len = (agentNumber.length + mac.length + deviceType.length + commandWord.length + modularOrder.length + orderContent.length + checkSum.length);//报文长度
        byte[] length = ByteUtils.int2bytesHL(2, len);//报文长度

        //除去报头和报尾其他部分的数据和，在程序中计算
        checkSum[0]=calculateSum(length,agentNumber,mac,deviceType,commandWord,modularOrder,orderContent);//校验和

        byte[] params = ByteUtils.mergeByteArray(head, length, agentNumber, mac, deviceType, commandWord, modularOrder, orderContent, checkSum, tail);
        return params;
    }

    public static Protocol generateProtocol(byte[] commandWord, byte[] modularOrder, byte[] orderContent) {
        byte[] head = {(byte) 0xBA};//报头

        byte[] agentNumber = CartApplication.getInstance().getAgentNumber();//代理商编号
        byte[] mac = CartApplication.getInstance().getMac();//MAC地址
        byte[] deviceType = {(byte) 0xFF};//设备类型
//        byte[] commandWord= {order};//命令字
//        byte[] modularOrder=modularOrder;//模块指令
//        byte[] orderContent=;//指令内容
        if (orderContent == null || orderContent.length == 0) {
            orderContent = new byte[]{0x00};
        }
        byte[] checkSum = new byte[1];//校验和
        byte[] tail = {(byte) 0xED};//报尾

        int len = (agentNumber.length + mac.length + deviceType.length + commandWord.length + modularOrder.length + orderContent.length + checkSum.length);//报文长度
        byte[] length = ByteUtils.int2bytesHL(2, len);//报文长度

        checkSum[0]=calculateSum(length,agentNumber,mac,deviceType,commandWord,modularOrder,orderContent);//校验和

        Protocol protocol=new Protocol(head, length, agentNumber, mac, deviceType, commandWord, modularOrder, orderContent, checkSum, tail);
        protocol.setType(Protocol.type_request);
        protocol.setProjectId(ProjectManager.getInstance().getProjectId());
        protocol.setStageId(ExperimentStageManager.getInstance().getStageId());
        return protocol;
    }

    public static byte calculateSum(byte[]... byteArrays){
        byte sum=0;
        for(int i=0;i<byteArrays.length;i++){
            byte[] bytes=byteArrays[i];
            for(int j=0;j<bytes.length;j++){
                sum+=bytes[j];
            }
        }
        return sum;
    }

    public static String getHexByte(byte[] b, int start, int length) {
        if(b==null||b.length==0){
            return "";
        }
        int end=start+length;
        if(end>b.length){
            end=b.length;
        }
        StringBuilder sb=new StringBuilder();
        for(int i=start;i<end;i++){
            sb.append(String.format(String.format("%02X ",b[i])));
        }
        if(sb.length()>0){
            sb.deleteCharAt(sb.length()-1);
        }
        return sb.toString();
    }

    //高位在前，低位在后
    public static byte[] int2bytesHL(int length, int num) {
        byte[] result = new byte[length];
        for (int i = 0; i < length; i++) {
            result[i] = (byte) ((num >>> (length - 1 - i) * 8) & 0xff);
        }
        return result;
    }

    //低位在前，高位在后
    public static byte[] int2bytesLG(int length, int num) {
        byte[] result = new byte[length];
        for (int i = 0; i < length; i++) {
            result[i] = (byte) ((num >>> i * 8) & 0xff);
        }
        return result;
    }

    //高位在前，低位在后
    public static int bytes2intHL(byte[] bytes) {
        int result = 0;
        int[] res = new int[bytes.length];
        for (int i = 0; i < bytes.length; i++) {
            res[i] = (bytes[i] & 0xff) << ((bytes.length - 1 - i) * 8);
            result |= res[i];
        }
        return result;
    }

    //低位在前，高位在后
    public static int bytes2intLH(byte[] bytes) {
        int result = 0;
        int[] res = new int[bytes.length];
        for (int i = 0; i < bytes.length; i++) {
            res[i] = (bytes[i] & 0xff) << (i * 8);
            result |= res[i];
        }
        return result;
    }

    public static byte[] mergeByteArray(byte[]... args) {
        int length = 0;
        for (int i = 0; i < args.length; i++) {
            length += args[i].length;
        }

        byte[] mergedByteArray = new byte[length];
        int index = 0;
        for (int i = 0; i < args.length; i++) {
            byte[] byteArray = args[i];
            for (int j = 0; j < byteArray.length; j++) {
                mergedByteArray[index] = byteArray[j];
                index++;
            }
        }

        return mergedByteArray;
    }

    public static boolean isEqual(byte[] bytes1, byte[] bytes2) {
        boolean isEqual = true;
        if ((bytes1 == null && bytes2 != null) || (bytes1 != null && bytes2 == null)) {//有一个是null
            isEqual = false;
        } else if (bytes1 == null && bytes2 == null) {//都是null
            isEqual = true;
        } else if (bytes1.length != bytes2.length) {//长度不等
            isEqual = false;
        } else {//长度相等
            for (int i = 0; i < bytes1.length; i++) {
                if (bytes1[i] != bytes2[i]) {
                    isEqual = false;
                    break;
                }
            }
        }
        return isEqual;
    }

    public static int byte2int(byte b) {
        return b & 0xff;
    }

    public static List<byte[]> delimiterBytes(byte[] buffer, byte delimiter) {
        List<byte[]> bytesArrayList = new ArrayList<>();
        int size = buffer.length;

        List<Integer> splited = new ArrayList();
        for (int i = 0; i < size; i++) {
            if (buffer[i] == delimiter) {
                splited.add(i);
            }
        }
        for (int i = 0; i < splited.size(); i++) {
            int start;
            if (i == 0) {
                start = 0;
            } else {
                start = splited.get(i - 1) + 1;
            }
            int end;
            end = splited.get(i) + 1;
            byte[] res = Arrays.copyOfRange(buffer, start, end);
            bytesArrayList.add(res);
        }

        return bytesArrayList;
    }

    public static int indexOf(byte[] bytes, byte target) {
        if (bytes == null) {
            return -1;
        }
        for (int i = 0; i < bytes.length; i++) {
            if (bytes[i] == target) {
                return i;
            }
        }
        return -1;
    }

    public static int[] indexsOf(byte[] bytes, byte target) {
        List<Integer> indexList=new ArrayList<>();
        if (bytes == null) {
            return null;
        }
        for (int i = 0; i < bytes.length; i++) {
            if (bytes[i] == target) {
                indexList.add(i);
            }
        }
        if(indexList.size()>0){
            int[] index=new int[indexList.size()];
            for(int i=0;i<indexList.size();i++){
                index[i]=indexList.get(i);
            }
            return index;
        }else {
            return null;
        }
    }

    public static int lastIndexOf(byte[] bytes, byte target) {
        int index = -1;
        if (bytes == null) {
            return index;
        }
        for (int i = 0; i < bytes.length; i++) {
            if (bytes[i] == target) {
                index = i;
            }
        }
        return index;
    }

    public static List<byte[]> delimiterBytes(byte[] src, byte head, byte tail) {
        List<byte[]> spliteBytes = new ArrayList<>();
        int head_index = ByteUtils.indexOf(src, head);
        int tail_index = ByteUtils.indexOf(src, tail);
        if (head_index != -1 && tail_index != -1) {//有HEAD和TAIL
            if (head_index != 0) {//HEAD不是在0位置
                byte[] bytes_beforeHEAD = Arrays.copyOfRange(src, 0, head_index);
                spliteBytes.add(bytes_beforeHEAD);
            }
            //HEAD和TAIL之间的bytes
            byte[] bytes = Arrays.copyOfRange(src, head_index, tail_index + 1);
            spliteBytes.add(bytes);
            if (tail_index != src.length - 1) {//TAIL不是在最后一位
                byte[] leftBytes = Arrays.copyOfRange(src, tail_index + 1, src.length);
                spliteBytes.addAll(delimiterBytes(leftBytes, head, tail));
            }
        } else {//HEAD和TAIL都没有
            spliteBytes.add(src);
        }
        return spliteBytes;
    }

    public static List<byte[]> delimiterBytes2(byte[] src, byte head, byte tail) {
        List<byte[]> spliteBytes = new ArrayList<>();
        int[] head_indexArray = indexsOf(src, head);
        if(head_indexArray==null){
            return null;
        }else {
            for (int i=0;i<head_indexArray.length;i++) {
                int head_index = head_indexArray[i];
                //HEAD不在最前面，丢弃HEAD前面的数据
//                if(head_index!=0){
//                    src=Arrays.copyOfRange(src,head_index,src.length);
//                    head_index=0;
//                }
                byte[] lenBytes=Arrays.copyOfRange(src,head_index+1, head_index+TestDecoder.lengthLength+1);
                int len=bytes2intHL(lenBytes);
                //长度大于报文总长度
                if((TestDecoder.headLength+TestDecoder.lengthLength+len+TestDecoder.tailLength)>(src.length-head_index)){
                    //如果只找到一个HEAD，或者这是最后一个HEAD，则这段报文可能还没接收完整
                    if(head_indexArray.length==1&&i==head_indexArray.length-1){
                        spliteBytes.add(Arrays.copyOfRange(src,head_index, src.length));
                    }
                }else {
                    byte lookingForTail = src[head_index+TestDecoder.headLength + TestDecoder.lengthLength + len];
                    //根据报文长度找到报尾
                    if (lookingForTail == TestDecoder.TAIL[0]) {
                        int totalLength = TestDecoder.headLength + TestDecoder.lengthLength + len + TestDecoder.tailLength;
                        byte[] bytes = Arrays.copyOfRange(src, head_index, head_index+totalLength);
                        spliteBytes.add(bytes);
                        if (totalLength < (src.length-head_index-totalLength)) {
                            byte[] leftBytes = Arrays.copyOfRange(src, head_index+totalLength, src.length);
                            spliteBytes.addAll(delimiterBytes2(leftBytes, head, tail));
                            break;
                        }
                    } else {//找到的报尾不对
//                    	byte[] bytes =Arrays.copyOfRange(src, head_index, head_index+headLength + lengthLength + len+ tailLength);
//                    	spliteBytes.add(bytes);
//                        src[head_index] = 0;//去除此报头，寻找下一个报头
//                        spliteBytes.addAll(delimiterBytes2(src, head, tail));
                    }
                }
            }
        }
        return spliteBytes;
    }

    public static List<byte[]> delimiterBytes3(byte[] src, byte head, byte tail) throws UnpackException {
        List<byte[]> spliteBytes = new ArrayList<>();
        int head_index = indexOf(src, head);
        if (head_index != 0) {
            return spliteBytes;
        }
        //报文长度的2个字节还没接收到，等待后续报文的接收
        if(src.length<TestDecoder.headLength + TestDecoder.lengthLength){
            spliteBytes.add(src);
            return spliteBytes;
        }
        byte[] lenBytes = Arrays.copyOfRange(src, head_index + 1, head_index + TestDecoder.lengthLength + 1);
        int len = bytes2intHL(lenBytes);
        // 长度大于报文总长度
        if ((TestDecoder.headLength + TestDecoder.lengthLength + len + TestDecoder.tailLength) > src.length) {
            // 报文可能出错，长度异常的大,报文长度可能是错误的任意值，从而导致长度不匹配
            if(len>255){
                throw new UnpackException("response length:"+ len + " too long",src);
            }else {
                // 报文可能还没接收完整，等待后续报文的接收
                spliteBytes.add(src);
            }
        } else {
            // 根据报文长度找到报尾
            byte lookingForTail = src[head_index + TestDecoder.headLength + TestDecoder.lengthLength + len];
            if (lookingForTail == tail) {// 报尾正确
                int totalLength = TestDecoder.headLength + TestDecoder.lengthLength + len + TestDecoder.tailLength;
                byte[] bytes = Arrays.copyOfRange(src, head_index, head_index + totalLength);
                spliteBytes.add(bytes);
                // 检测后面是否还有数据
                if (src.length - head_index - totalLength > 0) {// 有数据
                    byte[] leftBytes = Arrays.copyOfRange(src, head_index + totalLength, src.length);
                    spliteBytes.addAll(delimiterBytes3(leftBytes, head, tail));
                } else {// 没有后续数据，不做处理
                }
            }else {// 报尾错误
                throw new UnpackException("tail wrong",src);
            }
        }
        return spliteBytes;
    }
}
